import type { Customer } from "./idb.type";

class IDBService {
    private dbName: string;
    private dbVersion: number;
    private db: IDBDatabase | null;

    constructor(dbName: string = 'CustomerDB', dbVersion: number = 1) {
        this.dbName = dbName;
        this.dbVersion = dbVersion;
        this.db = null;
    }

    /**
     * open database connection
     * @returns {Promise<IDBDatabase>} db instance promise
     */
    open(): Promise<IDBDatabase> {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(this.dbName, this.dbVersion);
            request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
                const db = (event.target as IDBOpenDBRequest).result;
                this.db = db;

                if (!db.objectStoreNames.contains('customers')) {
                    const objectStore = db.createObjectStore('customers', { keyPath: 'id', autoIncrement: true });
                    objectStore.createIndex('name', 'name', { unique: false });
                    objectStore.createIndex('email', 'email', { unique: true });
                }
                console.log('Database create/upgrade completed');
            };

            // success event
            request.onsuccess = (event: Event) => {
                this.db = (event.target as IDBOpenDBRequest).result;
                console.info('Database opened successfully');
                resolve(this.db);
            };

            request.onerror = (event: Event) => {
                console.error('Database open error:', (event.target as IDBOpenDBRequest).error);
                reject((event.target as IDBOpenDBRequest).error);
            };
        });
    }

    /**
     * Close database connection
     */
    close(): void {
        console.info('Start closed Database connection');
        if (this.db) {
            this.db.close();
            this.db = null;
            console.info('Database closed successfully');
        }
    }

    // Add customer
    addCustomer(customer: Omit<Customer, 'id'>): Promise<Customer> {
        return new Promise((resolve, reject) => {
            // check db connection
            if (!this.db) {
                reject(new Error("Database not opened"));
                return;
            }

            // create transaction
            const transaction = this.db.transaction(['customers'], 'readwrite');
            // get object store
            const store = transaction.objectStore('customers');
            // add customer to object store
            const request = store.add(customer);

            // handle success event
            request.onsuccess = (event: Event) => {
                resolve({ ...customer, id: Number((event.target as IDBRequest).result) });
            };
            // handle error event
            request.onerror = (event: Event) => {
                reject((event.target as IDBRequest).error);
            };
        });
    }

    /**
     * Get all customers
     * @returns {Promise<Customer[]>} A promise that resolves to an array of customer objects
     */
    getAllCustomers(): Promise<Customer[]> {
        return new Promise((resolve, reject) => {
            // check db connection
            if (!this.db) {
                reject(new Error('Database not opened'));
                return;
            }
            // create transaction
            const transaction = this.db.transaction(['customers'], 'readonly');
            // get object store
            const store = transaction.objectStore('customers');
            // get all customers from object store
            const request = store.getAll();

            // handle success event
            request.onsuccess = (event: Event) => {
                const customers = (event.target as IDBRequest<Customer[]>).result;
                resolve(customers);
            };

            // handle error event
            request.onerror = (event: Event) => {
                const error = (event.target as IDBRequest<Customer[]>).error;
                console.error('Get all customers failed:', error);
                reject(error);
            };
        });
    }


    /**
     * Delete customer by id
     */
    deleteCustoemrById(id: number): Promise<number> {
        return new Promise((resolve, reject) => {
            if (!this.db) {
                reject(new Error('Database not opened'));
                return;
            }
            // create transaction
            const transaction = this.db.transaction(['customers'], 'readwrite');
            // get object store
            const store = transaction.objectStore('customers');
            // delete customer from object store
            const request = store.delete(id);
            // handle success event
            request.onsuccess = () => {
                resolve(id);
            };
            // handle error event
            request.onerror = (event: Event) => {
                reject((event.target as IDBRequest<number>).error);
            };
        });
    }
}

export default new IDBService();